/* exec_menu_demo.c - 基于用户输入选择执行不同的 exec 函数执行 ls -l 命令 */  

#define _GNU_SOURCE  // 启用 execvpe  
#include <stdio.h>  
#include <stdlib.h>  
#include <unistd.h>  
#include <string.h>  

/**  
 * 执行 execl 方法  
 */  
void execute_execl() {  
    printf("=== 使用 execl 执行 ls -l ===\n");  

    // execl 的参数依次为：路径，命令名，参数，NULL  
    execl("/bin/ls", "ls", "-l", (char *)NULL);  

    // 如果 exec 成功，以下代码不会执行  
    perror("execl 失败");  
    exit(EXIT_FAILURE);  
}  

/**  
 * 执行 execlp 方法  
 */  
void execute_execlp() {  
    printf("=== 使用 execlp 执行 ls -l ===\n");  

    // execlp 通过 PATH 环境变量查找可执行文件  
    execlp("ls", "ls", "-l", (char *)NULL);  

    // 如果 exec 成功，以下代码不会执行  
    perror("execlp 失败");  
    exit(EXIT_FAILURE);  
}  

/**  
 * 执行 execle 方法  
 */  
void execute_execle() {  
    printf("=== 使用 execle 执行 ls -l 并设置自定义环境变量 ===\n");  

    // 定义自定义环境变量  
    char *envp[] = { "PATH=/usr/bin:/bin", NULL };  

    // execle 的参数依次为：路径，命令名，参数，NULL，环境变量  
    execle("/bin/ls", "ls", "-l", (char *)NULL, envp);  

    // 如果 exec 成功，以下代码不会执行  
    perror("execle 失败");  
    exit(EXIT_FAILURE);  
}  

/**  
 * 执行 execv 方法  
 */  
void execute_execv() {  
    printf("=== 使用 execv 执行 ls -l ===\n");  

    // 定义参数列表，最后一个元素必须为 NULL  
    char *args[] = { "ls", "-l", NULL };  

    // execv 的参数依次为：路径，参数数组  
    execv("/bin/ls", args);  

    // 如果 exec 成功，以下代码不会执行  
    perror("execv 失败");  
    exit(EXIT_FAILURE);  
}  

/**  
 * 执行 execvp 方法  
 */  
void execute_execvp() {  
    printf("=== 使用 execvp 执行 ls -l ===\n");  

    // 定义参数列表，最后一个元素必须为 NULL  
    char *args[] = { "ls", "-l", NULL };  

    // execvp 通过 PATH 环境变量查找可执行文件  
    execvp("ls", args);  

    // 如果 exec 成功，以下代码不会执行  
    perror("execvp 失败");  
    exit(EXIT_FAILURE);  
}  

/**  
 * 执行 execvpe 方法  
 */  
void execute_execvpe_demo() {  
    printf("=== 使用 execvpe 执行 ls -l 并设置自定义环境变量 ===\n");  

    // 定义参数列表，最后一个元素必须为 NULL  
    char *args[] = { "ls", "-l", NULL };  

    // 定义自定义环境变量  
    char *envp[] = { "PATH=/usr/bin:/bin", NULL };  

    // execvpe 的参数依次为：文件名，参数数组，环境变量数组  
    execvpe("ls", args, envp);  

    // 如果 execvpe 成功，以下代码不会执行  
    perror("execvpe 失败");  
    exit(EXIT_FAILURE);  
}  

/**  
 * 显示菜单并获取用户选择  
 */  
int get_user_choice() {  
    int choice;  
    printf("请选择要执行的 exec 函数:\n");  
    printf("1. execl\n");  
    printf("2. execlp\n");  
    printf("3. execle\n");  
    printf("4. execv\n");  
    printf("5. execvp\n");  
    printf("6. execvpe\n");  
    printf("输入1-6: ");  

    if (scanf("%d", &choice) != 1) {  
        fprintf(stderr, "输入无效。\n");  
        // 清除输入缓冲区  
        int c;  
        while ((c = getchar()) != '\n' && c != EOF);  
        return -1;  // 返回无效选择  
    }  

    if (choice < 1 || choice > 6) {  
        fprintf(stderr, "选择无效，请输入1-6。\n");  
        return -1;  // 返回无效选择  
    }  

    return choice;  
}  

int main(void) {  
    while (1) {  
        int choice = get_user_choice();  

        if (choice == -1) {  
            // 输入无效，重新选择  
            continue;  
        }  

        switch (choice) {  
            case 1:  
                execute_execl();  
                break;  
            case 2:  
                execute_execlp();  
                break;  
            case 3:  
                execute_execle();  
                break;  
            case 4:  
                execute_execv();  
                break;  
            case 5:  
                execute_execvp();  
                break;  
            case 6:  
                execute_execvpe_demo();  
                break;  
            default:  
                fprintf(stderr, "未知的选择。\n");  
                exit(EXIT_FAILURE);  
        }  

        // 如果 exec 成功，以下代码不会执行  
        // 如果 exec 失败，允许用户重新选择  
        printf("执行失败，可以重新选择。\n");  
    }  

    return 0;  
}